package wsi.exp.exp3.compare;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.rygh.core.algorithm.OrderedPrecisionRecall;
import org.rygh.core.util.counter.SimpleCounter;
import org.rygh.core.xml.XmlPath;
import org.rygh.semantic.model.ex.PredicatePath;

import wsi.exp.exp3.GoldSetMatch;
import wsi.exp.exp3.PathMatchPair;
import wsi.function.Function;
import wsi.resolve.FactItem;

public class Exp3PairComparator extends Exp3Comparator {

	private final Set<PathMatchPair> hitPairSetInGold = new HashSet<>();
	private final Set<PathMatchPair> hitPairSetInResult = new HashSet<>();

	public Exp3PairComparator(Function function, int threshold) {
		super(function, threshold);
	}

	@Override
	public void calibrate() {
		PathMatchPair hit;

		List<PathMatchPair> pairs = new ArrayList<>();

		for (PathMatchPair pair : matchResult.getPairs()) {

			// if (pair.getPredicatePath().isTemp())
			// continue;

			// prevent 0.70 < 0.70, don't know why this is true for java.
			if (pair.getConfidence() + .000001 < .01 * threshold) {
				// System.out.printf("calibrate %s: %f < %f\n", e.getKey(),
				// counter.get(key).getPrecision(), threshold);
				continue;
			}

			pairs.add(pair);
		}

		sortPairs(pairs);

		for (PathMatchPair pair : pairs) {
			hit = goldSet.find(pair);

			recall.retrieve(hit != null);

			if (hit != null) {
				hitPairSetInGold.add(hit);
				hitPairSetInResult.add(pair);
			}
		}

		// log.info(String.format("hit count %d, total count %d", getHit(),
		// total));

	}

	@Deprecated
	public void calibrate(SimpleCounter<String> counter) {

		PredicatePath path;
		XmlPath xpath;
		PathMatchPair pair, hit;
		int retrieved = 0;

		for (Object obj : counter.valueSet()) {
			FactItem item = (FactItem) obj;

			// prevent 0.70 < 0.70, don't know why this is true for java.
			if (item.getPercentage() + .000001 < .01 * threshold) {
				// System.out.printf("calibrate %s: %f < %f\n", e.getKey(),
				// counter.get(key).getPrecision(), threshold);
				continue;
			}

			retrieved++;

			xpath = item.getXmlLeaf().getXpath();
			path = item.getCenterToValulePath();
			pair = new PathMatchPair(path, xpath);
			hit = goldSet.find(pair);

			if (hit != null)
				hitPairSetInGold.add(hit);
		}

		// log.info(String.format("hit count %d, total count %d", getHit(),
		// total));

		recall.setRelevant(hitPairSetInGold.size());
		recall.setRetrieved(retrieved);
	}

	@Override
	protected boolean checkHit(PathMatchPair pair, boolean gold) {
		return gold ? hitPairSetInGold.contains(pair) : hitPairSetInResult
				.contains(pair);
	}

	@Override
	public void setGoldSet(GoldSetMatch goldSet) {
		super.setGoldSet(goldSet);
		recall = new OrderedPrecisionRecall(goldSet.getGoldSizeByPair());
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();

		sb.append(String.format("%s:Precision %f\r\n", getName(),
				getPrecision()));
		sb.append(String.format("%s:Recall %f\r\n", getName(), getRecall()));
		sb.append(String.format("%s:Total %d\r\n", getName(),
				recall.getRetrieved()));
		sb.append(String.format("%s:Hit %d\r\n", getName(),
				recall.getRelevant()));

		if (getRecall() < 1)
			sb.append(String.format("Unhit relations\r\n%s\r\n",
					goldSet.getUnhit(hitPairSetInGold)));

		return sb.toString();
	}

}
